package com.fkcai.hansoul.common.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class RedisUtil {
	@Autowired
	private RedisTemplate<String, Object> redisTemplate;
	
	/* ============================== 通用操作 ============================== */
	
	/**
	 * 设置键的过期时间
	 *
	 * @param key     缓存键
	 * @param timeout 过期时间长度
	 * @param unit    时间单位（秒/分钟/小时等）
	 * @return 是否设置成功
	 */
	public Boolean expire (String key, long timeout, TimeUnit unit) {
		try {
			return redisTemplate.expire(key, timeout, unit);
		} catch (Exception e) {
			log.error("Redis expire 操作异常 | Key: {} | TTL: {}{} | 错误信息: {}",
					key, timeout, unit, e.getMessage());
			return false;
		}
	}
	
	/**
	 * 获取键的剩余过期时间
	 *
	 * @param key  缓存键
	 * @param unit 返回的时间单位
	 * @return 剩余时间（单位取决于unit参数），键不存在返回-2，永久键返回-1
	 */
	public Long getExpire (String key, TimeUnit unit) {
		try {
			return redisTemplate.getExpire(key, unit);
		} catch (Exception e) {
			log.error("Redis getExpire 操作异常 | Key: {} | 错误信息: {}", key, e.getMessage());
			return null;
		}
	}
	
	/**
	 * 检查键是否存在
	 *
	 * @param key 缓存键
	 * @return 键存在返回true，不存在返回false
	 */
	public Boolean hasKey (String key) {
		try {
			return redisTemplate.hasKey(key);
		} catch (Exception e) {
			log.error("Redis hasKey 操作异常 | Key: {} | 错误信息: {}", key, e.getMessage());
			return false;
		}
	}
	
	/**
	 * 删除一个或多个键
	 *
	 * @param keys 要删除的键（可变参数）
	 * @return 是否删除成功
	 */
	public Boolean delete (String... keys) {
		try {
			if (keys == null || keys.length == 0) return false;
			
			if (keys.length == 1) {
				return redisTemplate.delete(keys[0]);
			}
			
			return redisTemplate.delete(Arrays.asList(keys)) > 0;
		} catch (Exception e) {
			log.error("Redis del 操作异常 | Keys: {} | 错误信息: {}", Arrays.toString(keys), e.getMessage());
			return false;
		}
	}
	
	/* ============================== String 操作 ============================== */
	
	/**
	 * 设置字符串类型缓存（无过期时间）
	 *
	 * @param key   缓存键
	 * @param value 缓存值
	 */
	public void set (String key, Object value) {
		try {
			redisTemplate.opsForValue().set(key, value);
		} catch (Exception e) {
			log.error("Redis set 操作异常 | Key: {} | 错误信息: {}", key, e.getMessage());
		}
	}
	
	/**
	 * 设置字符串类型缓存并指定过期时间
	 *
	 * @param key     缓存键
	 * @param value   缓存值
	 * @param timeout 过期时间长度
	 * @param unit    时间单位
	 */
	public void setWithExpire (String key, Object value, long timeout, TimeUnit unit) {
		try {
			redisTemplate.opsForValue().set(key, value, timeout, unit);
		} catch (Exception e) {
			log.error("Redis setWithExpire 操作异常 | Key: {} | TTL: {}{} | 错误信息: {}",
					key, timeout, unit, e.getMessage());
		}
	}
	
	/**
	 * 仅在键不存在时设置缓存（原子操作）
	 *
	 * @param key   缓存键
	 * @param value 缓存值
	 * @return 设置成功返回true，键已存在返回false
	 */
	public Boolean setIfAbsent (String key, Object value) {
		try {
			return redisTemplate.opsForValue().setIfAbsent(key, value);
		} catch (Exception e) {
			log.error("Redis setIfAbsent 操作异常 | Key: {} | 错误信息: {}", key, e.getMessage());
			return false;
		}
	}
	
	/**
	 * 获取字符串类型缓存值
	 *
	 * @param key 缓存键
	 * @return 缓存值，键不存在返回null
	 */
	public Object get (String key) {
		try {
			return redisTemplate.opsForValue().get(key);
		} catch (Exception e) {
			log.error("Redis get 操作异常 | Key: {} | 错误信息: {}", key, e.getMessage());
			return null;
		}
	}
	
	/**
	 * 对数值类型的值进行增加操作（原子操作）
	 *
	 * @param key   缓存键
	 * @param delta 增加量（整数）
	 * @return 增加后的新值
	 */
	public Long increment (String key, long delta) {
		try {
			return redisTemplate.opsForValue().increment(key, delta);
		} catch (Exception e) {
			log.error("Redis increment 操作异常 | Key: {} | Delta: {} | 错误信息: {}",
					key, delta, e.getMessage());
			return null;
		}
	}
	
	/* ============================== Hash 操作 ============================== */
	
	/**
	 * 设置哈希表中字段的值
	 *
	 * @param key   哈希表键
	 * @param field 字段名
	 * @param value 字段值
	 */
	public void hashSet (String key, String field, Object value) {
		try {
			redisTemplate.opsForHash().put(key, field, value);
		} catch (Exception e) {
			log.error("Redis hashSet 操作异常 | Key: {} | Field: {} | 错误信息: {}",
					key, field, e.getMessage());
		}
	}
	
	/**
	 * 获取哈希表中字段的值
	 *
	 * @param key   哈希表键
	 * @param field 字段名
	 * @return 字段值，字段不存在返回null
	 */
	public Object hashGet (String key, String field) {
		try {
			return redisTemplate.opsForHash().get(key, field);
		} catch (Exception e) {
			log.error("Redis hashGet 操作异常 | Key: {} | Field: {} | 错误信息: {}",
					key, field, e.getMessage());
			return null;
		}
	}
	
	/**
	 * 获取哈希表的所有字段和值
	 *
	 * @param key 哈希表键
	 * @return 包含所有字段和值的Map对象，键不存在返回空Map
	 */
	public Map<Object, Object> hashGetAll (String key) {
		try {
			return redisTemplate.opsForHash().entries(key);
		} catch (Exception e) {
			log.error("Redis hashGetAll 操作异常 | Key: {} | 错误信息: {}", key, e.getMessage());
			return Collections.emptyMap();
		}
	}
	
	/**
	 * 删除哈希表中的一个或多个字段
	 *
	 * @param key    哈希表键
	 * @param fields 要删除的字段（可变参数）
	 * @return 实际删除的字段数量
	 */
	public Long hashDelete (String key, Object... fields) {
		try {
			return redisTemplate.opsForHash().delete(key, fields);
		} catch (Exception e) {
			log.error("Redis hashDelete 操作异常 | Key: {} | Fields: {} | 错误信息: {}",
					key, Arrays.toString(fields), e.getMessage());
			return 0L;
		}
	}
	
	/**
	 * 检查哈希表中是否存在指定字段
	 *
	 * @param key   哈希表键
	 * @param field 字段名
	 * @return 字段存在返回true，不存在返回false
	 */
	public Boolean hashHasKey (String key, String field) {
		try {
			return redisTemplate.opsForHash().hasKey(key, field);
		} catch (Exception e) {
			log.error("Redis hashHasKey 操作异常 | Key: {} | Field: {} | 错误信息: {}",
					key, field, e.getMessage());
			return false;
		}
	}
	
	/* ============================== List 操作 ============================== */
	
	/**
	 * 从列表左侧插入元素（L_PUSH操作）
	 *
	 * @param key   列表键
	 * @param value 要插入的元素值
	 * @return 插入后列表的长度
	 */
	public Long listLeftPush (String key, Object value) {
		try {
			return redisTemplate.opsForList().leftPush(key, value);
		} catch (Exception e) {
			log.error("Redis listLeftPush 操作异常 | Key: {} | 错误信息: {}", key, e.getMessage());
			return 0L;
		}
	}
	
	/**
	 * 从列表右侧插入元素（R_PUSH操作）
	 *
	 * @param key   列表键
	 * @param value 要插入的元素值
	 * @return 插入后列表的长度
	 */
	public Long listRightPush (String key, Object value) {
		try {
			return redisTemplate.opsForList().rightPush(key, value);
		} catch (Exception e) {
			log.error("Redis listRightPush 操作异常 | Key: {} | 错误信息: {}", key, e.getMessage());
			return 0L;
		}
	}
	
	/**
	 * 从列表左侧弹出元素（L_POP操作）
	 *
	 * @param key 列表键
	 * @return 弹出的元素值，列表为空返回null
	 */
	public Object listLeftPop (String key) {
		try {
			return redisTemplate.opsForList().leftPop(key);
		} catch (Exception e) {
			log.error("Redis listLeftPop 操作异常 | Key: {} | 错误信息: {}", key, e.getMessage());
			return null;
		}
	}
	
	/**
	 * 从列表右侧弹出元素（R_POP操作）
	 *
	 * @param key 列表键
	 * @return 弹出的元素值，列表为空返回null
	 */
	public Object listRightPop (String key) {
		try {
			return redisTemplate.opsForList().rightPop(key);
		} catch (Exception e) {
			log.error("Redis listRightPop 操作异常 | Key: {} | 错误信息: {}", key, e.getMessage());
			return null;
		}
	}
	
	/**
	 * 获取列表指定范围内的元素
	 *
	 * @param key   列表键
	 * @param start 起始索引（0表示第一个元素）
	 * @param end   结束索引（-1表示最后一个元素）
	 * @return 包含指定范围内元素的列表
	 */
	public List<Object> listRange (String key, long start, long end) {
		try {
			return redisTemplate.opsForList().range(key, start, end);
		} catch (Exception e) {
			log.error("Redis listRange 操作异常 | Key: {} | Start: {} | End: {} | 错误信息: {}",
					key, start, end, e.getMessage());
			return Collections.emptyList();
		}
	}
	
	/**
	 * 获取列表长度
	 *
	 * @param key 列表键
	 * @return 列表的元素数量
	 */
	public Long listSize (String key) {
		try {
			return redisTemplate.opsForList().size(key);
		} catch (Exception e) {
			log.error("Redis listSize 操作异常 | Key: {} | 错误信息: {}", key, e.getMessage());
			return 0L;
		}
	}
	
	/* ============================== Set 操作 ============================== */
	
	/**
	 * 向集合中添加元素
	 *
	 * @param key    集合键
	 * @param values 要添加的元素（可变参数）
	 * @return 成功添加的新元素数量（重复元素不计入）
	 */
	public Long setAdd (String key, Object... values) {
		try {
			return redisTemplate.opsForSet().add(key, values);
		} catch (Exception e) {
			log.error("Redis setAdd 操作异常 | Key: {} | 错误信息: {}", key, e.getMessage());
			return 0L;
		}
	}
	
	/**
	 * 从集合中移除元素
	 *
	 * @param key    集合键
	 * @param values 要移除的元素（可变参数）
	 * @return 成功移除的元素数量
	 */
	public Long setRemove (String key, Object... values) {
		try {
			return redisTemplate.opsForSet().remove(key, values);
		} catch (Exception e) {
			log.error("Redis setRemove 操作异常 | Key: {} | 错误信息: {}", key, e.getMessage());
			return 0L;
		}
	}
	
	/**
	 * 检查元素是否在集合中
	 *
	 * @param key   集合键
	 * @param value 要检查的元素
	 * @return 元素存在返回true，不存在返回false
	 */
	public Boolean setIsMember (String key, Object value) {
		try {
			return redisTemplate.opsForSet().isMember(key, value);
		} catch (Exception e) {
			log.error("Redis setIsMember 操作异常 | Key: {} | 错误信息: {}", key, e.getMessage());
			return false;
		}
	}
	
	/**
	 * 获取集合的所有元素
	 *
	 * @param key 集合键
	 * @return 包含所有元素的Set集合
	 */
	public Set<Object> setMembers (String key) {
		try {
			return redisTemplate.opsForSet().members(key);
		} catch (Exception e) {
			log.error("Redis setMembers 操作异常 | Key: {} | 错误信息: {}", key, e.getMessage());
			return Collections.emptySet();
		}
	}
	
	/**
	 * 获取集合的大小
	 *
	 * @param key 集合键
	 * @return 集合的元素数量
	 */
	public Long setSize (String key) {
		try {
			return redisTemplate.opsForSet().size(key);
		} catch (Exception e) {
			log.error("Redis setSize 操作异常 | Key: {} | 错误信息: {}", key, e.getMessage());
			return 0L;
		}
	}
	
	/* ============================== Sorted Set 操作 ============================== */
	
	/**
	 * 向有序集合中添加元素
	 *
	 * @param key   有序集合键
	 * @param value 元素值
	 * @param score 元素分数（用于排序）
	 * @return 添加成功返回true，元素已存在（分数更新）返回false
	 */
	public Boolean sortedSetAdd (String key, Object value, double score) {
		try {
			return redisTemplate.opsForZSet().add(key, value, score);
		} catch (Exception e) {
			log.error("Redis sortedSetAdd 操作异常 | Key: {} | Score: {} | 错误信息: {}",
					key, score, e.getMessage());
			return false;
		}
	}
	
	/**
	 * 获取有序集合中指定分数范围内的元素
	 *
	 * @param key 有序集合键
	 * @param min 最小分数（包含）
	 * @param max 最大分数（包含）
	 * @return 包含指定范围内元素的Set集合
	 */
	public Set<Object> sortedSetRangeByScore (String key, double min, double max) {
		try {
			return redisTemplate.opsForZSet().rangeByScore(key, min, max);
		} catch (Exception e) {
			log.error("Redis sortedSetRangeByScore 操作异常 | Key: {} | Min: {} | Max: {} | 错误信息: {}",
					key, min, max, e.getMessage());
			return Collections.emptySet();
		}
	}
	
	/**
	 * 获取有序集合中元素的分数
	 *
	 * @param key   有序集合键
	 * @param value 元素值
	 * @return 元素的分数，元素不存在返回null
	 */
	public Double sortedSetScore (String key, Object value) {
		try {
			return redisTemplate.opsForZSet().score(key, value);
		} catch (Exception e) {
			log.error("Redis sortedSetScore 操作异常 | Key: {} | 错误信息: {}", key, e.getMessage());
			return null;
		}
	}
	
	/**
	 * 从有序集合中移除元素
	 *
	 * @param key    有序集合键
	 * @param values 要移除的元素（可变参数）
	 * @return 成功移除的元素数量
	 */
	public Long sortedSetRemove (String key, Object... values) {
		try {
			return redisTemplate.opsForZSet().remove(key, values);
		} catch (Exception e) {
			log.error("Redis sortedSetRemove 操作异常 | Key: {} | 错误信息: {}", key, e.getMessage());
			return 0L;
		}
	}
	
	/* ============================== 分布式锁 ============================== */
	
	/**
	 * 获取分布式锁（原子操作）
	 *
	 * @param key     锁的键
	 * @param value   锁的值（推荐使用唯一标识，如UUID）
	 * @param timeout 锁的超时时间
	 * @param unit    时间单位
	 * @return 获取锁成功返回true，失败返回false
	 */
	public Boolean acquireLock (String key, String value, long timeout, TimeUnit unit) {
		try {
			return redisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit);
		} catch (Exception e) {
			log.error("Redis acquireLock 操作异常 | Key: {} | Value: {} | 错误信息: {}",
					key, value, e.getMessage());
			return false;
		}
	}
	
	/**
	 * 释放分布式锁（原子操作）
	 *
	 * @param key   锁的键
	 * @param value 锁的值（必须与获取锁时使用的值相同）
	 * @return 释放锁成功返回true，失败返回false
	 */
	public Boolean releaseLock (String key, String value) {
		try {
			// 使用Lua脚本保证原子性
			String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
					"return redis.call('del', KEYS[1]) " +
					"else " +
					"return 0 " +
					"end";
			DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
			Long result = redisTemplate.execute(redisScript, Collections.singletonList(key), value);
			return result != null && result == 1;
		} catch (Exception e) {
			log.error("Redis releaseLock 操作异常 | Key: {} | Value: {} | 错误信息: {}",
					key, value, e.getMessage());
			return false;
		}
	}
	
	/* ============================== 管道批量操作 ============================== */
	
	/**
	 * 使用管道批量设置键值对（高性能批量操作）
	 *
	 * @param keyValues 包含键值对的Map
	 * @return 操作结果列表
	 */
	public List<Object> pipelineSet (Map<String, Object> keyValues) {
		try {
			return redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
				keyValues.forEach((key, value) ->
						connection.stringCommands().set(key.getBytes(),
								((RedisSerializer<Object>) redisTemplate
										.getValueSerializer())
										.serialize(value)));
				return null;
			});
		} catch (Exception e) {
			log.error("Redis pipelineSet 操作异常 | 错误信息: {}", e.getMessage());
			return Collections.emptyList();
		}
	}
}